ant自动版本构建

之前写信乎的时候,需求用jenkins进行版本构建,当时照着师傅的构建脚本修改写了写,是用ant跑的,现在as的版本构建工具都使用gradle了,回顾一下吧。

流程

打包需要借助JDK和Android SDK中的工具,这些工具的路径在不同的开发人员和系统中可能会不同,所以,我们将这些需要修改的地方,放在build.properties配置文件中,如下:

1
os.home=/home/leleliu008

jdk.home=${os.home}/bin/jdk1.7.0_67
jarsigner=${jdk.home}/bin/jarsigner

android.sdk.home=${os.home}/bin/adt-bundle-linux-x86_64-20140702/sdk
android.sdk.platform=${android.sdk.home}/platforms/android-19

aapt=${android.sdk.home}/build-tools/17.0.0/aapt
aidl=${android.sdk.home}/build-tools/17.0.0/aidl
dx=${android.sdk.home}/build-tools/17.0.0/dx
apk-builder=${android.sdk.home}/tools/apkbuilder
zipalign=${android.sdk.home}/tools/zipalign

proguard.home=${android.sdk.home}/tools/proguard/lib
proguard.config=proguard.cfg

keystore.path=debug.keystore
keystore.password=android
keystore.key=androiddebugkey

1,使用aapt工具生成R.java文件

Ant和命令行使用android SDK提供的aapt程序生成R.java。
Ant脚本如下:

<target name="gen-R-java" depends="make-dirs">
    <echo>Generating R.java / Manifest.java from the resources...</echo>
    <exec executable="${aapt}" failonerror="true">
        <arg value="package" />
        <arg value="-m" />
        <arg value="-J" />
        <arg value="${gen.dir}" />
        <arg value="-M" />
        <arg value="AndroidManifest.xml" />
        <arg value="-S" />
        <arg value="${res.dir}" />
        <arg value="-I" />
        <arg value="${android-jar}" />
    </exec>
</target>
1
2
3

### 2,使用aidl工具将.aidl文件转换成.java文件
使用了aidl进程通信机制的时候,需要将.aidl文件转换成Java类,使用aidl工具可以完成此工作,如下:
``` <target name="aidl" depends="make-dirs"> <echo>Compiling aidl files into Java classes...</echo> <apply executable="${aidl}" failonerror="true"> <arg value="-p${android.sdk.platform}/framework.aidl" /> <arg value="-I${src.dir}" /> <arg value="-o${gen.dir}" /> <fileset dir="src"> <include name="**/*.aidl" /> </fileset> </apply> </target>
### 3,使用javac工具将.java文件编译成.class文件 Ant已经内置了javac任务,可以直接使用该任务完成Java的编译,如下:








1
2
3
4


### 4,使用proground对.class文件进行混淆
混淆能够对代码进行优化,更符合计算机执行的效率,更重要的是让反编译后的代码看起来晦涩难懂,达到保护代码的作用。

``` <target name="obfuscate" depends="compile"> <echo>Obscure the class files....</echo> <jar basedir="${classes.dir}" destfile="${out.dir}/temp.jar"/> <java jar="${proguard.home}/proguard.jar" fork="true" failonerror="true"> <jvmarg value="-Dmaximum.inlined.code.length=32"/> <jvmarg value="-Xmx512M"/> <arg value="-injars ${out.dir}/temp.jar"/> <arg value="-outjars ${out.dir}/obfuscate.jar"/> <arg value="-libraryjars ${android-jar}" /> <arg value="@${proguard.config}"/> </java> <delete file="${out.dir}/temp.jar"/> <delete dir="${classes.dir}"/> <mkdir dir="${classes.dir}"/> <unzip src="${out.dir}/obfuscate.jar" dest="${classes.dir}"/> <delete file="${out.dir}/obfuscate.jar"/> </target>

5,使用dx工具处理将所有的.class文件转换成一个.dex文件

Android的dalvik虚拟机不同于JVM,他不能直接执行.class文件,必须将这些.class文件经过优化打包到一个.dex文件中,以提升执行效率,如下:

1


<target name="dex">
    <echo>Converting compiled files and external libraries into ${dex-file}...</echo>
    <apply executable="${dx}" failonerror="true" parallel="true">
        <arg value="--dex" />
        <arg value="--output=${dex-file}" />
        <arg path="${classes.dir}" />
        <fileset dir="${libs.dir}" includes="*.jar" />
    </apply>
</target>

6,使用aapt工具打包资源文件

1

<target name="package-res-and-assets">
    <echo>Packaging resources and assets...</echo>
    <exec executable="${aapt}" failonerror="true">
        <arg value="package" />
        <arg value="-f" />
        <arg value="-M" />
        <arg value="AndroidManifest.xml" />
        <arg value="-S" />
        <arg value="${res.dir}" />
        <arg value="-A" />
        <arg value="${assets.dir}" />
        <arg value="-I" />
        <arg value="${android-jar}" />
        <arg value="-F" />
        <arg value="${resources-file}" />
    </exec>
</target>

对照R.java文件的生成,可以看到参数发生了变化,少了-m 和 -J,如果看aapt用法中的描述就知道,-m和-J是结对出现的,用以指明R.java文件的生成路径。-M、-S、-I之前都有提到,这里不再介绍。 -F的作用是指明打包后的资源文件的路径,在最后一定要加上文件名,最好加上扩展名。这里参考Eclipse中自动编译时制定的.ap_后缀名。

7,使用apkbuilder生成未签名的apk安装文件

需要注意的是apkbuilder这个工具从API 17开始,不再提供了,所以,我们只能找到之前这个工具,放入对应的位置,即可使用。

1

<target name="gen-unsigned-apk" depends="dex, package-res-and-assets">
    <echo>Packaging ${unsigned-out-file} for release...</echo>
    <exec executable="${apk-builder}" failonerror="true">
        <arg value="${unsigned-out-file}" />
        <arg value="-u" />
        <arg value="-z" />
        <arg value="${resources-file}" />
        <arg value="-f" />
        <arg value="${dex-file}" />
        <arg value="-rf" />
        <arg value="${src.dir}" />
        <arg value="-rj" />
        <arg value="${libs.dir}" />
        <arg value="-nf" />
        <arg value="${libs.dir}" />
    </exec>
    <echo>It will need to be signed with jarsigner before being published.</echo>
</target>

8,使用jdk中的jarsigner对未签名的apk文件进行签名

Android应用程序必须进行签名,否则无法安装。同时,我们也可以进行签名验证,以防二次打包。
Ant脚本:


<target name="sign-apk" depends="gen-unsigned-apk">
    <exec executable="${jarsigner}" failonerror="true">
        <arg value="-verbose" />
        <arg value="-storepass" />
        <arg value="${keystore.password}" />
        <arg value="-keystore" />
        <arg value="${keystore.path}" />
        <arg value="-digestalg" />
        <arg value="SHA1" />
        <arg value="-sigalg" />
        <arg value="MD5withRSA" />
        <arg value="-sigfile" />
        <arg value="CERT" />
        <arg value="-signedjar" />
        <arg value="${signed-out-file}" />
        <arg value="${unsigned-out-file}" />
        <arg value="${keystore.key}" />
    </exec>
</target>

1
2


### 9,使用zipalign对签名后的apk文件进行字节对齐优化
Android SDK中包含一个“zipalign”的工具,它能够对打包的应用程序进行优化,使得在运行时Android与应用程序间的交互更加有效率。因此,这种方式能够让应用程序和整个系统运行得更快。 Ant脚本: ``` <target name="zipalign" depends="sign-apk"> <exec executable="${zipalign}" failonerror="true"> <arg value="-v" /> <arg value="-f" /> <arg value="4" /> <arg value="${signed-out-file}" /> <arg value="${zipalign-out-file}" /> </exec> </target>
### 10,Debug和release版本 一般Debug版本,打开Log开关,不进行混淆,这样便于排查问题,而release版本用于真实情况,所以会把Log开关关闭,并且进行混淆,所以,我们一般会提供两个版本,两个版本的流程基本上一样,只是个别地方不同。 Debug版本的打包:
1


<target name="debug">
    <echo>Packaging debug package...</echo>
	    <replaceregexp byline="true">
        <regexp pattern="false"/>
        <substitution expression="true"/>
        <fileset dir="${basedir}/src/com/datatang/client/base/" includes="DebugLog.java"/>
    </replaceregexp>
	<antcall target="compile" />
	<antcall target="zipalign" />
</target>
release版本的打包:
1


<target name="release">
    <echo>Packaging release package...</echo>
    <replaceregexp byline="true">
        <regexp pattern="true"/>
        <substitution expression="false"/>
        <fileset dir="${basedir}/src/com/datatang/client/base/" includes="DebugLog.java"/>
    </replaceregexp>
	<antcall target="obfuscate" />	
	<antcall target="zipalign" />
</target>
由于代码的版本控制工具使用的是SVN,所以,我们需要将SVN上指定的SVN提交号或者是最新的代码先导出到本地,然后根据Debug和release版本依次进行上面的流程,即可完成打包工具了。 这个工作使用了Shell脚本完成,这里使用Shell脚本的原因是: 1,一般的服务器是GNU/Linux系统,可以方便的执行Shell脚本,我们可以将这个脚本部署在服务器上。 2,SVN客户端工具在Windows上没有命令行工具,只有GUI工具,如果要使用Ant还需要依赖其他的Jar包,也不方便。 3,我们鼓励开发人员使用GNU/Linux系统进行开发Android程序。 打包完成后,需要将apk上传到SVN的指定目录,如果打包成功,还需要在SVN上创建一个该版本对应的Tag,脚本如下:

projectDir=http://192.168.1.24/pro/department/factory/project/DataTang_for_Android;

tagsDir=$projectDir/02.%E5%BC%80%E5%8F%91/source/tags;

apkDir=$projectDir/01.%E4%BA%A7%E5%93%81/%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%89%88%E6%9C%AC;

repositoryUrl=$projectDir/02.%E5%BC%80%E5%8F%91/source/trunk/DatatangForAndroid;

repositoryUserName=liufupin@datatang.com;
repositoryPassword=shujutang1508

1
2
3


先删除存放源码的目录:

``` echo Deleting directory $PWD/project rm -rf project

导出源码到本地:

1

echo Check out begain, please wait patiently!
svn export -r HEAD --username $repositoryUserName --password $repositoryPassword $repositoryUrl project
echo Check out over!

切换到存放源码的目录:

cd project

1
2
3

获取AndroidManifest.xml中的版本号:

``` versionName=`cat AndroidManifest.xml | grep 'versionName="[^"]*"' | sed 's/.*versionName="\([^"]*\)".*/\1/'`; echo $versionName;
获取build.properties配置的os.home变量的值,因为不同系统的不同用户,这个值可能不同:

oldHome=/home/leleliu008
newHome=$HOME

sed -i “s#${oldHome}#${newHome}#g” build.properties

1
2

打release包

ant release

1
将release包上传到SVN指定目录中:

svn import –username $repositoryUserName –password $repositoryPassword bin/DataTang_for_android.apk $apkDir/DataTang_forandroid$versionName(obfuscate).apk -m “import $versionName obfuscate apk”

1
打debug包:

ant debug

1
2

将release包上传到SVN指定目录中:

svn import –username $repositoryUserName –password $repositoryPassword bin/DataTang_for_android.apk $apkDir/DataTang_forandroid$versionName.apk -m “import $versionName unobfuscate apk”

1
2

构建完成后,先删除bin目录和gen目录,因为这些目录是构建过程中生成的,不需要提交到SVN中:

rm -rf bin
rm -rf gen

1
2

在SVN上创建该版本的tag:

svn import –username $repositoryUserName –password $repositoryPassword project $tagsDir/DatatangForAndroid_$versionName -m “create tag $versionName” –no-ignore

1
2
3

### 11,渠道包
在Android项目的根目录下面有一个channel文件夹,里面有一个渠道号的配置文件channels.txt,如下:

100000
100001
100002
100003
100004
100005
100005
100006
100007
100008
100009

1
2
3


打渠道包的shell脚本:

``` #!/bin/sh baseDir=$PWD; if [-d packages]; then rm -rf packages; fi mkdir packages; cat channels.txt | while read line do echo began build channel $line; sed -i "s#[0-9]\{6\}#${line}#g" $baseDir/../src/com/datatang/client/common/config/ChannelConfig.java sh autobuild.sh; cd packages; mkdir $line; cd .. mv $baseDir/../bin/DataTang_for_android.apk $baseDir/packages/$line/DataTang_for_android_$line.apk done

12,部署

操作系统:CentOS 7 x86_64
主机地址:192.168.1.48
主机用户名:root
主机密码:Simple1921

打包需要使用Android SDK中的工具,所以,必须安装Android SDK。
需要使用SVN进行管理源代码,所以必须安装SVN客户端。